<?php

use app\service\auth;
use app\service\config;
use app\service\poster;
use app\service\sms;
use Illuminate\Database\Capsule\Manager as DB;

class UserController extends CommonController
{
    protected $authExcept = ['accountLogin', 'smsLogin', 'forgotPwd', 'register', 'wxOfficialAccountOauth', 'getWxMiniProgramSessionKey', 'wxMiniProgramOauth'];

    public function testAction()
    {
        json(['code' => 1, 'msg' => 'ok', 'data' => '']);
    }

    public function accountLoginAction()
    {
        $account = $this->getPost('account');
        $password = $this->getPost('password');
        if (!$account || !$password) {
            throw new Exception('账号和密码不能为空');
        }
        $member = memberModel::where('id', $account)->orWhere('phone', $account)->first();
        if (!$member) {
            throw new Exception('账号不存在');
        }
        if ($member->password != md5($password . $member->salt)) {
            $member->try_times += 1;
            if ($member->try_times >= 5) {
                $member->lock_until = strtotime('+20 minute');
                $member->save();
                throw new Exception('密码错误连续5次以上，账号已被锁定，请稍后再试');
            } else {
                $member->save();
                throw new Exception('密码不正确');
            }
        }
        if ($member->status == 'lock' || $member->lock_until > time()) {
            throw new Exception('账号被锁定，请稍后再试');
        }
        $data = auth::login($member);
        $data['weakpwd'] = auth::checkWeakPassword($password);
        json(['code' => 1, 'msg' => '登录成功', 'data' => $data]);
    }

    public function smsLoginAction()
    {
        $mobile = $this->getPost('mobile');
        $code = $this->getPost('code');
        if (!$mobile || !$code) {
            throw new Exception('手机号和验证码不能为空');
        }
        $member = memberModel::where('phone', $mobile)->first();
        if (!$member) {
            throw new Exception('账号不存在');
        }
        if ($member->status == 'lock') {
            throw new Exception('账号被锁定');
        }
        if (!\app\service\sms::check($mobile, $code, 'mobilelogin')) {
            throw new Exception('验证码不正确');
        }
        json(['code' => 1, 'msg' => '登录成功', 'data' => auth::login($member)]);
    }

    public function forgotPwdAction()
    {
        $params = [
            'mobile' => $this->getPost('mobile'),
            'code' => $this->getPost('code'),
            'password' => $this->getPost('password'),
        ];
        try {
            Validate::check($params, [
                'mobile' => ['func' => 'isPhone', 'msg' => '手机号'],
                'code' => ['role' => 'required|len:4', 'msg' => '验证码'],
                'password' => ['role' => 'required|minlen:6|maxlen:16', 'msg' => '密码'],
            ]);
        } catch (Exception $e) {
            throw new Exception($e->getMessage());
        }

        $user = memberModel::firstWhere('phone', $params['mobile']);
        if (empty($user)) {
            throw new Exception('该手机号未注册用户');
        }

        if (!sms::check($params['mobile'], $params['code'], 'resetpwd')) {
            throw new Exception('验证码不正确');
        }
        sms::flush($params['mobile']);

        $salt = substr(uniqid(), 0 ,8);
        $user->salt = $salt;
        $user->password = md5($params['password'] . $salt);
        $user->save();
        json(['code' => 1, 'msg' => '找回密码成功']);
    }

    // 微信自动登录 start

    public function wxOfficialAccountOauthAction()
    {
        $params = $this->get();
        $payload = json_decode(htmlspecialchars_decode($params['payload']), true);

        // 解析前端主机
        if ($payload['event'] !== 'login' && $payload['token'] !== '') {
            // 校验登录状态
        }

        $app = (new WechatLibrary('wxOfficialAccount'))->getApp();
        $oauth = $app->oauth;
        $code = $params['code'];
        $user = $oauth->userFromCode($code);
        $decryptData = $user->toArray();
        if (!empty($payload['spm'])) {
            $decryptData['parent_member_id'] = $payload['spm'];
        }
        $token = DB::transaction(function () use ($payload, $decryptData) {
            return $this->getOauthToken(
                $payload['event'],
                $decryptData,
                'wxOfficialAccount',
                'Wechat',
                $payload['token'] ?? ''
            );
        });
        // 跳转回前端
        if ($token) {
            header('Location: ' . $payload['host'] . 'pages/public/loading/?token=' . $token);
        } else {
            header('Location: ' . $payload['host']);
        }
        exit;
    }

    private function getOauthToken($event, $oauthData, $platform, $provider, $token = '')
    {
        Log::out('wx:' . json_encode($oauthData), 'wxoauthlogin');

        if ($platform === 'wxMiniProgram' || $platform === 'App') {
            $oauthData['expire_in'] = 7200;
            $oauthData['expiretime'] = time() + 7200;
        }

        $userOauth = memberoauthModel::where('openid', $oauthData['id'])
            ->where('platform', $platform)
            ->where('provider', $provider)
            ->first();
        $member_id = $userOauth->member_id ?? 0;

        switch ($event) {
            case 'login':               // 登录(自动注册)
                if (empty($userOauth)) {      // 没有找到第三方登录信息 创建新用户
                    $userOauth = $this->createNewWxOauth($oauthData, $provider, $platform);
                }
                $member = memberModel::find($member_id);
                if (empty($member)) {
                    $nickname = $oauthData['nickname'] ?? ('User-' . uniqid());
                    $password = '';
                    $avatar = $oauthData['avatar'] ?? '';
                    $inviter = memberModel::find($oauthData['parent_member_id'] ?? 0);
                    if (isset($oauthData['parent_member_id']) && empty($inviter)) {
                        throw new Exception('未查找到匹配的邀请人');
                    }
                    $member = auth::register($nickname, $password, $inviter, ['avatar' => $avatar]);
                }
                $userOauth->member_id = $member->id;
                $userOauth->save();
                $loginData = auth::login($member);
                return $loginData['token'];
            case 'refresh':
                $member = memberModel::firstWhere('token', $token);
                $member->nickname = $oauthData['nickname'];
                $member->avatar = $oauthData['avatar'];
                $member->save();
                break;
            case 'bind':
                $member = memberModel::firstWhere('token', $token);
                if (empty($userOauth)) {      // 没有找到第三方登录信息 创建新用户
                    $this->createNewWxOauth($oauthData, $provider, $platform, $member->id);
                } else {
                    $userOauth->member_id = $member->id;
                    $userOauth->save();
                }
                $member->nickname = $oauthData['nickname'];
                $member->avatar = $oauthData['avatar'];
                $member->save();
                break;
        }

        return $member->token;
    }

    private function createNewWxOauth($oauthData, $provider, $platform, $member_id = 0)
    {
        $oauth = new memberoauthModel();
        $oauth->member_id = $member_id;
        $oauth->provider = $provider;
        $oauth->platform = $platform;
        $oauth->openid = $oauthData['id'];
        $oauth->unionid = $oauthData['unionid'] ?? '';
        $oauth->nickname = $oauthData['nickname'];
        $oauth->sex = $oauthData['raw']['sex'] ?? 0;
        $oauth->country = $oauthData['raw']['country'] ?? '';
        $oauth->province = $oauthData['raw']['province'] ?? '';
        $oauth->city = $oauthData['raw']['city'] ?? '';
        $oauth->headimgurl = $oauthData['avatar'] ?? '';
        $oauth->logintime = time();
        $oauth->logincount = 1;
        $oauth->expire_in = $oauthData['expire_in'] ?? null;
        $oauth->refresh_token = $oauthData['refresh_token'];
        $oauth->access_token = $oauthData['access_token'];
        $oauth->created_at = timestamp();
        $oauth->save();
        return $oauth;
    }

    public function unbindthirdoauthAction()
    {
        $member = auth::getUser();
        $platform = $this->getPost('platform');
        $provider = $this->getPost('provider');

        if (empty($member->phone)) {
            throw new Exception('请先绑定手机号再进行解绑操作');
        }

        memberoauthModel::where('platform', $platform)
            ->where('provider', $provider)
            ->where('member_id',  $member->id)
            ->delete();
        json(['code' => 1, 'msg' => '解绑成功']);
    }

    // 微信自动登录 end

    public function existmobileAction()
    {
        $user = auth::getUser();
        $mobile = $this->getPost('mobile');
        $exist = memberModel::where('phone', $mobile)->first();
        if ($exist && $exist->id != $user->id) {
            json(['code' => 1010, 'msg' => '', 'data' => ['id' => $exist->id]]);
        } else {
            json(['code' => 1, 'msg' => '']);
        }
    }

    public function bindmobileAction()
    {
        $member = auth::getUser();
        $params = [
            'mobile' => $this->getPost('mobile'),
            'code' => $this->getPost('code'),
        ];
        try {
            Validate::check($params, [
                'mobile' => ['func' => 'isPhone', 'msg' => '手机号'],
                'code' => ['role' => 'required|len:4', 'msg' => '验证码'],
            ]);
        } catch (Exception $e) {
            throw new Exception($e->getMessage());
        }
        if (!sms::check($params['mobile'], $params['code'], 'register')) {
            throw new Exception('验证码不正确', 30001);
        }
        sms::flush($params['mobile']);

        $exist = memberModel::firstWhere('phone', $params['mobile']);
        if ($exist && $exist->id!==$member->id) {
            \app\service\member::merge($member->id, $exist->id, 'user', $member->id, '会员操作绑定手机号时合并账号');
        }

        \memberModel::where('id', $member->id)->update(['phone' => $params['mobile']]);
        json(['code' => 1, 'msg' => '绑定成功']);
    }

    public function registerAction()
    {
        $params = [
            'mobile' => $this->getPost('mobile'),
            'code' => $this->getPost('code'),
            'password' => $this->getPost('password'),
            'inviterId' => $this->getPost('inviterId'),
        ];
        try {
            Validate::check($params, [
                'mobile' => ['func' => 'isPhone', 'msg' => '手机号'],
                'code' => ['role' => 'required|len:4', 'msg' => '验证码'],
                'password' => ['role' => 'required|minlen:6|maxlen:16', 'msg' => '密码'],
                'inviterId' => ['func' => 'isInteger', 'msg' => '邀请人ID'],
            ]);
        } catch (Exception $e) {
            throw new Exception($e->getMessage());
        }

        if (memberModel::firstWhere('phone', $params['mobile'])) {
            throw new Exception('手机号已存在');
        }

        if (!sms::check($params['mobile'], $params['code'], 'register')) {
            throw new Exception('验证码不正确');
        }
        sms::flush($params['mobile']);

        if (!empty($params['inviterId'])) {
            $inviter = memberModel::where('id', $params['inviterId'])->orWhere('phone', $params['inviterId'])->first();
            if (!$inviter) {
                throw new Exception('未查找到匹配的邀请人');
            }
        }

        $member = DB::transaction(function () use ($params, $inviter) {
            $nickname = 'User-' . uniqid();
            $password = $params['password'];
            if (auth::checkWeakPassword($password)) {
                throw new Exception('您的密码过于简单，为保障您的账户资金安全，请将密码修改为字母+数字');
            }
            return auth::register($nickname, $password, $inviter ?? null, ['phone' => $params['mobile']]);
        });

        if (!$member) {
            throw new Exception('注册失败');
        }
        $member->nickname = 'User-' . $member->id;
        $member->save();

        json(['code' => 1, 'msg' => '登录成功', 'data' => auth::login($member)]);
    }

    public function indexAction()
    {
        $userinfo = auth::userinfo();
        json(['code' => 1, 'msg' => '用户信息', 'data' => $userinfo]);
    }

    public function changepwdAction()
    {
        $params = [
            'oldpassword' => $this->getPost('oldpassword'),
            'newpassword' => $this->getPost('newpassword'),
        ];
        try {
            Validate::check($params, [
                'oldpassword' => ['role' => 'required|minlen:6|maxlen:16', 'msg' => '旧密码'],
                'newpassword' => ['role' => 'required|minlen:6|maxlen:16', 'msg' => '新密码'],
            ]);
        } catch (Exception $e) {
            throw new Exception($e->getMessage());
        }
        $user = auth::getUser();
        if (!$user || $user->password != md5($params['oldpassword'] . $user->salt)) {
            throw new Exception('旧密码不正确');
        }
        if (auth::checkWeakPassword($params['newpassword'])) {
            throw new Exception('您的密码过于简单，为保障您的账户资金安全，请将密码修改为字母+数字');
        }
        $user->password = md5($params['newpassword'] . $user->salt);
        $user->save();
        json(['code' => 1, 'msg' => '修改密码成功']);
    }

    public function userDataAction()
    {
        // DB::enableQueryLog();
        $data = auth::userdata();
        // $data['log'] = DB::getQueryLog();
        json(['code' => 1, 'msg' => '用户数据', 'data' => $data]);
    }

    public function userinfoAction()
    {
        if ($this->get('id')) {
            $member = memberModel::find($this->get('id'));
        }
        $data = auth::userdata($member ?? null);
        json(['code' => 1, 'msg' => '用户数据', 'data' => $data]);
    }

    public function makeposterAction()
    {
        $userInfo = auth::userinfo();
        $avatar = $userInfo['avatar'];
        if (empty($avatar)) {
            $avatar = $this->config->application->hostUrl . '/images/base_avatar.png';
        }
        if (!preg_match('#^http#', $avatar)) {
            $avatar = $this->config->application->hostUrl . $avatar;
        }
        $qrcode = $this->getPost('qrcode');
        $share_config = config::get('share');

        $session_key = 'user_' . $userInfo['id'] . '_posterBg';
        $index = (int) Cache::get($session_key);
        $count = count($share_config['user_poster_bg']);
        if ($index < $count) {
            $index += 1;
        }
        if ($index >= $count) {
            $index = 0;
        }
        Cache::set($session_key, $index);

        $date = date('Ymd');
        $descdir = dirname(dirname(APP_PATH)) . "/public/poster/{$date}";
        if (!is_dir($descdir)) {
            if (!mkdir($descdir,0777,true)) {
                throw new Exception('无法创建海报目录');
            }
        }

        $spm = explode("spm=", $qrcode)[1] ?? '';
        $parseSpm = explode('.', $spm);
        $goodsId = $parseSpm[2] ?? '';
        $posterBg = $goodsId ? $share_config['goods_poster_bg'] : $share_config['user_poster_bg'][$index];
        $extension = pathinfo($posterBg)['extension'];

        $user_id = $userInfo['id'];
        $filename = "/poster/{$date}/pg_{$user_id}_{$index}_{$goodsId}.{$extension}";

        $element = [
            'id'       => 'ID：' . $user_id,
            'avatar'   => $avatar,
            'nickname' => $userInfo['nickname'],
            'qrcode'   => "http://qr.curr.cn/?size=8&data=" . urlencode($qrcode),
        ];

        $filepath = APP_PATH . "/public{$filename}";
        poster::make($posterBg, $element, $filepath);
        $posterUrl = ($this->config->application->hostUrl ?? '') . "{$filename}?v" . time();

        if (!empty($this->config->application->cdn->enable) && file_exists($filepath)) {
            $postData = [
                'token'     => md5($filepath . ENCRYPT_IV),
                'file_path' => $filepath,
                'file_body' => base64_encode(file_get_contents($filepath))
            ];
            $res = json_decode(request('http://files.zmssp.cn/files/upload', $postData), true);
            if($res['ret']==0){
                $posterUrl = "http://files.zmssp.cn{$filename}?v" . time();
            }
        }

        json(['code' => 1, 'msg' => '生成海报成功', 'data' => $posterUrl]);
    }

    public function userrecommendAction ()
    {
        $member = auth::getUser();
        $inviter = memberModel::find($member->parent_member_id);
        json(['code' => 1, 'msg' => '用户数据', 'data' => $inviter ? auth::userinfo($inviter) : null]);
    }

    public function thirdOauthInfoAction()
    {
        $data = $userinfo = auth::thirdoauthinfo();
        json(['code' => 1, 'msg' => '第三方用户授权信息', 'data' => $data], 'json', '', false);
    }

    public function profileAction()
    {
        $user = auth::getUser();
        $params = [
            'avatar' => $this->getPost('avatar', ''),
            'birthday' => $this->getPost('birthday', ''),
            'nickname' => $this->getPost('nickname', ''),
            'realname' => $this->getPost('realname', ''),
        ];
        $params = array_filter($params);
        foreach ($params as $key => $val) {
            $user->$key = $val;
        }
        $user->save();
        json(['code' => 1, 'msg' => '保存成功']);
    }

    public function bindingparentAction()
    {
        $params = $this->getPost();
        Validate::check($params, [
            'inviterId' => ['role'=>'required', 'msg'=>'邀请人标识'],
        ]);
        if(memberModel::where('id', $params['inviterId'])->orWhere('phone', $params['inviterId'])->doesntExist()){
            ret(30002, '邀请人ID或手机号不存在');
        }
        json(['code' => 1, 'msg' => '绑定成功', 'data' => auth::bindParentUser($params['inviterId'])]);
    }

    public function bindingmobileparentAction()
    {
        $params = $this->getPost();
        Validate::check($params, [
            'inviterId' => ['role'=>'required', 'msg'=>'邀请人标识'],
            'mobile'    => ['role'=>'required', 'msg'=>'手机号'],
            'code'      => ['role'=>'required', 'msg'=>'验证码'],
        ]);
        if (!smscodeModel::where('mobile', $params['mobile'])->where('code', $params['code'])->where('created_at', '>', date('Y-m-d H:i:s', time()-300))->exists()){
            ret(30002, '验证码不正确');
        }
        json(['code' => 1, 'msg' => '绑定成功', 'data' => auth::bindMobileParent($params)]);
    }

    public function forgotPayPwdAction()
    {
        $params = [
            'mobile' => $this->getPost('mobile'),
            'payPwd' => $this->getPost('pay_pwd'),
            'captcha' => $this->getPost('code'),
        ];
        try {
            Validate::check($params, [
                'mobile' => ['func'=>'isPhone', 'msg'=>'手机号'],
                'payPwd' => ['role'=>'required|len:6', 'msg'=>'支付密码'],
                'captcha' => ['role'=>'required', 'msg'=>'验证码'],
            ]);
        } catch (Exception $e) {
            throw new Exception($e->getMessage());
        }
        $mobile = $params['mobile'];
        $payPwd = $params['payPwd'];
        $captcha = $params['captcha'];
        $user = auth::getUser();
        if ($user->phone != $mobile) {
            throw new Exception('未绑定此号码');
        }
        if (!sms::check($mobile, $captcha, 'resetpaypwd')) {
            throw new Exception('验证码不正确');
        }
        if ($payPwd=='123456' || preg_match('#(\d)\1{5}#', $payPwd) ) {
            throw new Exception('密码过于简单'); //TODO:密码复杂度校验
        }

        sms::flush($mobile);
        $user->pay_password = md5($payPwd);
        $user->save();
        json(['code' => 1, 'msg' => '支付密码重置成功', 'data' => '']);
    }

    public function changePayPwdAction()
    {
        $user = auth::getUser();
        $oldPayPwd = $this->getPost("old_pay_pwd");
        $payPwd = $this->getPost("pay_pwd");

        if ($user->pay_password && (strlen($user->pay_password) > 3)) {
            if (!$oldPayPwd || strlen($oldPayPwd) < 6) {
                throw new Exception('请输入旧密码');
            }
            if ($user->pay_password != md5($oldPayPwd)) {
                throw new Exception('旧密码输入错误');
            }

            if ($user->pay_password == md5($payPwd)) {
                throw new Exception('旧密码与新密码相同');
            }
        }

        if (!$payPwd || strlen($payPwd) != 6) {
            throw new Exception('请输入6位数密码'); //TODO:密码规则校验
        }

        if ($payPwd=='123456' || preg_match('#(\d)\1{5}#', $payPwd) ) {
            throw new Exception('密码过于简单'); //TODO:密码复杂度校验
        }

        $user->pay_password = md5($payPwd);
        $user->save();
        json(['code' => 1, 'msg' => '支付密码设置成功', 'data' => '']);
    }

    public function logoutAction()
    {
        auth::logout();
        json(['code' => 1, 'msg' => '注销登录成功']);
    }

    public function pickgoodscardamountAction()
    {
        $user = auth::getUser();
        $data = \app\modules\Admin\models\memberpickgoodscardModel::where('member_id', $user->id)
            ->where(function ($query) {
                $query->whereNull('expire')->orWhere('expire', '>', date('Y-m-d H:i:s'));
            })
            ->sum('money');
        json(['code' => 1, 'msg' => '提货卡金额', 'data' => $data]);
    }

    public function pickgoodscardAction()
    {
        $type = $this->get('type', 'valid');
        $page = $this->get('page', 1);
        $per_page = $this->get('per_page', 10);
        $user = auth::getUser();
        $timestamp = timestamp();
        if ($type == 'valid') {
            $total = \app\modules\Admin\models\memberpickgoodscardModel::where('member_id', $user->id)
                ->whereRaw("money>0 and (expire is null or expire>'{$timestamp}')")
                ->count();
            $data = \app\modules\Admin\models\memberpickgoodscardModel::where('member_id', $user->id)
                ->whereRaw("money>0 and (expire is null or expire>'{$timestamp}')")
                ->orderBy('id', 'desc')
                ->offset(($page - 1) * $per_page)
                ->limit($per_page)
                ->get();
        } else {
            $total = \app\modules\Admin\models\memberpickgoodscardModel::withTrashed()->where('member_id', $user->id)
                ->whereRaw("(money<=0 or (expire is not null and expire<'{$timestamp}'))")
                ->count();
            $data = \app\modules\Admin\models\memberpickgoodscardModel::withTrashed()->whereRaw("(money<=0 or (expire is not null and expire<'{$timestamp}'))")
                ->orderBy('money', 'desc')
                ->orderBy('id', 'desc')
                ->offset(($page - 1) * $per_page)
                ->limit($per_page)
                ->get();
        }

        foreach ($data as $item) {
            $card_ids[] = $item->card_id;
        }
        $cards = DB::table('pickgoods_card')->whereIn('id', array_unique($card_ids ?? []))->get();
        foreach ($data as $item) {
            $item->created_at = date('Y-m-d', strtotime($item->created_at));
            $item->expire = $item->expire ? date('Y-m-d', strtotime($item->expire)) : '长期有效';
            foreach ($cards as $card_item) {
                if ($card_item->id == $item->card_id) {
                    $item->amount = $card_item->amount;
                }
            }
            $list[] = $item;
        }

        $result = [
            'current_page' => $page,
            'last_page' => ceil($total / $per_page),
            'per_page' => $per_page,
            'total' => $total,
            'data' => $list ?? [],
        ];
        json(['code' => 1, 'msg' => '提货卡', 'data' => $result]);
    }

    public function pickgoodscardlogAction()
    {
        $id = $this->get('id', 0);
        $date = $this->get('date', '');
        $page = $this->get('page', 1);
        $per_page = $this->get('per_page', 10);

        $date = explode('-', $date);

        $query = DB::table('member_pickgoods_log')->where('member_pickgoods_card_id', $id);
        if (!empty($date)) {
            array_walk($date, function (&$item, $key) {
                $item = $key == 1 ? $item . ' 23:59:59' : $item;
                $item = timestamp(strtotime($item));
            });
            $query->whereBetween('created_at', $date);
        }

        $total_money = $query->sum('money');
        $total = $query->count();
        $data = $query->orderBy('id', 'desc')
            ->offset(($page - 1) * $per_page)
            ->limit($per_page)
            ->get();

        foreach ($data as $item) {
            $order_ids[] = $item->event_id;
        }
        $orders = orderModel::whereIn('id', array_unique($order_ids ?? []))->get();
        $orderitems = orderitemModel::whereIn('order_id', array_unique($order_ids ?? []))->get();
        foreach ($data as $item) {
            foreach ($orders as $order_item) {
                if ($order_item->id == $item->event_id) {
                    $item->order_sn = $order_item->order_sn;
                    $item->order_status_name = $order_item->status_name;

                    $item->order_items = [];
                    foreach ($orderitems as $orderitem_item) {
                        if ($orderitem_item->order_id == $order_item->id) {
                            $item->order_items[] = $orderitem_item;
                        }
                    }
                    break;
                }
            }
            $list[] = $item;
        }

        $result = [
            'total_money' => $total_money,
            'current_page' => $page,
            'last_page' => ceil($total / $per_page),
            'per_page' => $per_page,
            'total' => $total,
            'data' => $list ?? [],
        ];
        json(['code' => 1, 'msg' => '使用记录', 'data' => $result]);
    }

    public function upgradecodeListAction()
    {
        $user = auth::getUser();
        $page = $this->get('page', 1);
        $per_page = $this->get('per_page', 10);

        $level_list = agentlevelModel::get();
        $total = DB::table('upgrade_code')->where('member_id_relation', $user->id)->count();
        $list = DB::table('upgrade_code')
            ->where('member_id_relation', $user->id)
            ->offset(($page - 1) * $per_page)
            ->limit($per_page)
            ->get();
        $data = [];
        foreach ($list as $item) {
            foreach ($level_list as $level_item) {
                if ($level_item->level == $item->level) {
                    $item->level_name = $level_item->name;
                    break;
                }
            }
            $data[] = $item;
        }
        $result = [
            'current_page' => $page,
            'last_page' => ceil($total / $per_page),
            'per_page' => $per_page,
            'total' => $total,
            'data' => $data,
        ];

        json(['code' => 1, 'msg' => '升级码列表', 'data' => $result]);
    }

    public function upgradecodeUseAction()
    {
        $user = auth::getUser();
        $upgrade_code = $this->get('upgrade_code', '');
        $find = DB::table('upgrade_code')->where('code', $upgrade_code)->first();
        if (empty($find)) {
            json(['code' => 0, 'msg' => '升级码不存在']);
            exit;
        }
        if ($find->status == 'used') {
            json(['code' => 0, 'msg' => '升级码已被使用']);
            exit;
        }
        if ($find->status == 'disabled') {
            json(['code' => 0, 'msg' => '升级码不可用']);
            exit;
        }
        if ($user->level >= $find->level) {
            json(['code' => 0, 'msg' => '当前等级已达到升级码对应等级']);
            exit;
        }
        DB::transaction(function () use ($find, $user) {
            \app\service\member::level(
                $user->id,
                $find->level,
                'user',
                $user->id,
                '使用升级码变更账号等级'
            );
            DB::table('upgrade_code')->where('id', $find->id)->update([
                'time_use' => timestamp(),
                'member_id_use' => $user->id,
                'status' => 'used',
            ]);
            $user->demotion_lock = 1;
            $user->save();
        });
        $level = agentlevelModel::where('level', $find->level)->first();
        json(['code' => 1, 'msg' => '您已成功升级为:' . $level->name ?? '']);
    }

    public function getWxMiniProgramSessionKeyAction()
    {
        $post = $this->input();
        $autoLogin = $post['autoLogin'];
        $wechat = new WechatLibrary('wxMiniProgram');
        $decryptSession = $wechat->code($post['code']);
        if (!isset($decryptSession['session_key'])) {
            throw new Exception('未获取session_key,请重启应用');
        }
        Cache::set($decryptSession['session_key'], $decryptSession, 24 * 3600 * 31); // 强制31天过期
        $userOauth = memberoauthModel::where([
            'provider' => 'Wechat',
            'platform' => 'wxMiniProgram',
            'openid'   => $decryptSession['openid']
        ])->first();
        if ($userOauth) {
            $userOauth->session_key = $decryptSession['session_key'];
            $userOauth->save();
        }
        if ($autoLogin && $userOauth) {
            $mem = memberModel::find($userOauth->member_id);
            if ($mem) {
                $token = $mem->token;
                json(['code' => 1, 'msg' => '登陆成功', 'data' => ['token' => $token, 'session_key' => $decryptSession['session_key'], 'openid' => $decryptSession['openid']]]);
            } else {
                json(['code' => 0, 'msg' => '登陆失败']);
            }
        } else {
            json(['code' => 1, 'msg' => '', 'data' => $decryptSession]);
        }
    }

    public function wxMiniProgramOauthAction()
    {
        $post = $this->input();
        $token = DB::transaction(function () use ($post) {
            try {
                $wechat = new WechatLibrary('wxMiniProgram');
                $decryptSession = Cache::get($post['session_key']);
                if (!$decryptSession || !isset($decryptSession['openid'])) {
                    throw new \Exception('未获取到登录态,请重试');
                }
                $decryptUserInfo = $wechat->decryptData($post['session_key'], $post['iv'], $post['encryptedData']); // 客户端传值数据都不可信，需服务端解密用户信息
                $decryptUserInfo = array_merge($decryptUserInfo, $decryptSession);
                //组装decryptData
                $decryptData = array_change_key_case($decryptUserInfo, CASE_LOWER);
                if (empty($decryptData['openid'])) {
                    throw new \Exception('code错误,请重试');
                }
                $decryptData['headimgurl'] = $decryptData['avatarurl'];
                $decryptData['sex'] = $decryptData['gender'];
                $decryptData['session_key'] = $post['session_key'];
                return $this->oauthLoginOrRegisterOrBindOrRefresh($post['event'], $decryptData, 'wxMiniProgram', 'Wechat');
            } catch (\Exception $e) {
                throw new \Exception($e->getMessage());
            }
        });

        if ($token) {
            json(['code' => 1, 'msg' => 'Logged in successful', 'data'=> ['token' => $token]]);
        } else {
            throw new \Exception('login failed');
        }
    }

    private function oauthLoginOrRegisterOrBindOrRefresh($event, $decryptData, $platform, $provider, $keeptime = 0)
    {
        $oauthData = $decryptData;
        $oauthData = array_merge($oauthData, [
            'provider' => $provider,
            'platform' => $platform,

        ]);
        if ($platform === 'wxMiniProgram' || $platform === 'App') {
            $oauthData['expire_in'] = 7200;
            $oauthData['expiretime'] = time() + 7200;
        }
        $userOauth = memberoauthModel::where('openid', $decryptData['openid'])
            ->where('platform', $platform)
            ->where('provider', $provider)
            ->where('member_id', '<>', 0)
            ->lockForUpdate(true)
            ->first();

        $token = '';
        switch ($event) {
            case 'login':               // 登录(自动注册)
                if (!$userOauth) {      // 没有找到第三方登录信息 创建新用户
                    //默认创建新用户
                    $user_id = 0;
                    $createNewUser = true;
                    $oauthData['logintime'] = time();
                    $oauthData['logincount'] = 1;
                    // 判断是否有unionid 并且已存在oauth数据中
                    if (isset($oauthData['unionid'])) {
                        //存在同厂商信息，添加oauthData数据，合并用户
                        $userUnionOauth = memberoauthModel::where(['unionid' => $oauthData['unionid'], 'provider' => $provider])->first();
                        if ($userUnionOauth) {
                            $existUser = memberModel::find($userUnionOauth->member_id);
                            if ($existUser) {
                                $createNewUser = false;
                            }
                        }
                    }

                    // 创建空用户
                    if ($createNewUser) {
                        $username = randStr(20);
                        $password = '';
                        $domain = Tools::getHttpHost();
                        $extend = [];
                        $extend['nickname'] = $oauthData['nickname'] ? $oauthData['nickname'] : $extend['nickname'];
                        $extend['avatar'] = $oauthData['headimgurl'] ? $oauthData['headimgurl'] : $extend['avatar'];
                        if (isset($oauthData['parent_user_id'])) {
                            $extend['parent_user_id'] = $oauthData['parent_user_id'];
                        }
                        $mem = auth::register($oauthData['nickname'], $password, $oauthData['parent_user_id'],  $extend);
                        $user_id = $mem->id;
                        if (empty($oauthData['nickname'])) {
                            $mem->nickname = $username . $mem->id;
                            $mem->save();
                        }
                        $token = $mem->token;
                    }
                    $oauthData['member_id'] = $user_id;
                    $oauthData['created_at'] = date('Y-m-d H:i:s');
                    unset($oauthData['parent_user_id']);
                    $this->cleanTableColumn('member_oauth', $oauthData);
                    memberoauthModel::insert($oauthData);
                } else {
                    // 找到第三方登录信息，直接登录
                    $user_id = $userOauth->member_id;
                    if ($mem = memberModel::find($user_id)) {       // 获取到用户
                        $oauthData['logincount'] = $userOauth->logincount + 1;
                        $oauthData['logintime'] = time();
                        $userOauth->save($oauthData);
                        $token = $mem->token;
                    } else {         // 用户已被删除 重新执行登录
                        $userOauth->member_id = 0;
                        $userOauth->save();
                        $this->oauthLoginOrRegisterOrBindOrRefresh($event, $decryptData, $platform, $provider);
                    }
                }
                break;
            case 'refresh':
                if (!$userOauth) {
                    throw new \Exception('未找到第三方授权账户');
                }
                if (!empty($oauthData['nickname'])) {
                    $refreshFields['nickname'] = $oauthData['nickname'];
                }
                if (!empty($oauthData['headimgurl'])) {
                    $refreshFields['avatar'] = $oauthData['headimgurl'];
                }
                $mem = auth::userinfo();
                $mem->nickname = $oauthData['nickname'];
                $mem->avatar = $oauthData['headimgurl'];
                $mem->save();
                $userOauth->save();
                break;
            case 'bind':
                $mem = auth::userinfo();
                if (!$mem) {
                    throw new \Exception('请先登录');
                }
                $oauthData['member_id'] = $mem->id;
                if ($userOauth) {
                    if ($userOauth['member_id'] != 0 && $userOauth['member_id'] != $mem->id && memberModel::find($userOauth['member_id'])) {
                        throw new \Exception('该账号已被其他用户绑定');
                    }
                    $oauthData['id'] = $userOauth->id;
                    $userOauth->update($oauthData);
                } else {
                    $oauthData['logincount'] = 1;
                    $oauthData['logintime'] = time();
                    $oauthData['createtime'] = time();
                    $this->cleanTableColumn('member_oauth', $oauthData);
                    memberoauthModel::insert($oauthData);
                }
                break;
        }
        return $token;
//        if ($auth = auth::login()) {
//            return $auth['token'];
//        }
    }

    private function getUserDefaultFields()
    {
        $userConfig = json_decode(config::get(['name' => 'user'])->value, true);
        return $userConfig;
    }

}
